#pragma once 
#include<iostream>
#include<assert.h> 
 
using std::cout;
using std::endl;
using std::cin;
using std::ostream;
using std::istream;
using std::initializer_list;
using std::string;

namespace liu {
	template <class T> 
	class vector {
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		iterator begin() {
			return _start;
		}
		iterator end() {
			return _finish;
		}
		const_iterator begin() const {
			return  _start;
		}
		const_iterator end() const {
			return  _finish;
		}
		vector()
		{
		}
		vector(const vector<T>& s) {
			reserve(s.capacity());
			for (auto e : s) {
				push_back(e);
			}

		}
		/*vector(size_t n, const T& val = T()) {
			reserve(n);
			for (size_t i = 0; i < n; i++) {
				push_back(val);
			}
		}*/ 
		vector(int n, const T& val = T()) {
			reserve(n);
			for (size_t i = 0; i < n; i++) {
				push_back(val);
			}
		}

		vector(initializer_list<T> il) {
			reserve(il.size());
			for (auto e : il) {
				push_back(e);
			}
		}

		void swap(vector<T>& s) {
			std::swap(_start, s._start);
			std::swap(_finish, s._finish);
			std::swap(_endOfStorage, s._endOfStorage);
		}
		vector<T>& operator=(vector<T> s) {
			swap(s);
			return *this; 
		}
		template<class InputIterator>
		vector(InputIterator first, InputIterator last) {
			while (first != last) {
				push_back(*first);
				first++;
			}
		}


		~vector() {
			delete[] _start;
			_start = _finish = _endOfStorage = nullptr;
		}
		
		const size_t size() const {
			return _finish - _start;
		}
		const size_t capacity() const {
			return _endOfStorage - _start;
		}
		T& operator[](size_t pos) {
			assert(pos < size());
			return *(_start + pos);
		}

		void push_back(const T val) {
			/*if (_finish == _endOfStorage) {
				size_t oldsize = size();
				size_t newcapcity = capcity() == 0 ? 4 : capcity() * 2;
				T* tmp = new T[newcapcity];
				memcpy(tmp, _start, oldsize * sizeof(T));
				delete[] _start;
				_start = tmp;
				_finish = _start + oldsize;
				_endOfStorage = _start + newcapcity;
			 } 
			*_finish = val;
			++ _finish;*/
			insert(_finish, val);
		}
		bool empty() {
			return _start == _finish;
		}

		void pop_back() {
			/*assert(! empty());
			_finish--;*/
			erase(_finish - 1);
		}

		void reserve(size_t newcapcity) {
			size_t oldsize = size();
			T* tmp = new T[newcapcity];
			/*memcpy(tmp, _start, oldsize * sizeof(T));*/
			for (size_t i = 0; i < oldsize; i++) {
				tmp[i] = _start[i];
			}
			delete[] _start;
			_start = tmp;
			_finish = _start + oldsize;
			_endOfStorage = _start + newcapcity;
		}
		void resize(size_t n,const T& val= T()) {
			if (n > size()) {
				reserve(n);
				size_t dist = n - size();
				for (size_t i = 0; i < dist; i++) {
					*_finish = val;
					_finish++;
				}
			}
			if (n <= size()) {
				size_t dist = size() - n;
				for (size_t i = 0; i < dist; i++) {
					_finish--;
				}
			}
		}
		void insert(iterator pos,const T& val) {
			assert((pos - _start) >= 0 && (_finish - pos) >= 0);
			size_t oldsize = size();
			size_t dist = pos-_start;
			if (_finish == _endOfStorage) {	
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				/*size_t newcapcity = capcity() == 0 ? 4 : capcity() * 2;
				T* tmp = new T[newcapcity];
				memcpy(tmp, _start, oldsize * sizeof(T));
				delete[] _start;
				_start = tmp;
				_finish = _start + oldsize;
				_endOfStorage = _start + newcapcity;*/
			}
			pos = _start + dist;
			while ((_finish-pos) > 0) {
				*_finish = *(_finish-1);
				_finish--;
			}
			*pos = val;
			_finish =_start+ oldsize + 1;

		}

		iterator erase(iterator pos) {
			assert(!empty());
			assert((pos - _start) >= 0 && (_finish - pos) >0);
			iterator it = pos;
			while (it != _finish) {
				*it = *(it + 1);
				it++;
			}
			_finish--;
			return pos;
		}


		void printf_vector(const vector<T>& s) {
			/*for (size_t i = 0; i < s1.size(); i++) {
				cout << s1[i] << " ";
			}*/
			/*cout << endl;*/

			//vector<T>::const_iterator it = s.begin();
			//while (it != s.end()) {
			//	//cout << *it << " ";
			//	it++;
			//}
			//cout << endl;


			for (auto e : s) {
				cout << e << " ";
			}
			cout << endl;
		}

	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _endOfStorage = nullptr;

	};
	void test1() {
		vector<int> s1;
		s1.push_back(1);
		s1.push_back(2);
		s1.push_back(3);
		s1.push_back(4);
		s1.push_back(5);
		s1.push_back(6);
		s1.push_back(7);
		s1.printf_vector(s1); 
		//vector<double> s2;
		//s2.push_back(1.1);
		//s2.push_back(2.2);
		//s2.push_back(3.3);
		//s2.push_back(4.4);
		//s2.printf_vector(s2);
		//s1.pop_back();
		//s1.pop_back();
		//s1.pop_back();
		///*s1.pop_back();
		//s1.pop_back();
		//s1.pop_back();
		//s1.pop_back(); s1.pop_back();*/
		//s1.printf_vector(s1);
	}
	void test2() {
		vector<int> s1;
		s1.push_back(1);
		s1.push_back(2);
		s1.push_back(3);
		s1.push_back(4);
		s1.push_back(5);
		s1.push_back(6);
		s1.push_back(7);
		s1.printf_vector(s1);
		s1.insert(s1.begin()+2, 20);
		s1.insert(s1.begin() + 2, 20);
		s1.insert(s1.begin() + 2, 20);
		/*s1.insert(s1.begin() + 2, 20);*/
		//s1.insert(s1.begin() + 2, 20);
		//s1.insert(s1.begin() + 20, 40);
		s1.printf_vector(s1);
	}

	void test3() {
		vector<int> s1;
		s1.push_back(1);
		s1.push_back(2);
		s1.push_back(3);
		s1.push_back(4);
		s1.push_back(5);
		s1.printf_vector(s1);
		/*s1.resize(3);*/
		/*s1.resize(10,1);*/
		//s1.erase(s1.begin()+2);
		//s1.erase(s1.begin() + 2);
		//s1.erase(s1.begin() + 2);
		///*s1.erase(s1.begin() + 2);*/
		//s1.erase(s1.begin() + 1);
		////s1.erase(s1.begin() + 1);
		//s1.printf_vector(s1);
		s1.pop_back();
		s1.printf_vector(s1);
	}
	void test4() {
		vector<int> s1;
		s1.push_back(1);
		s1.push_back(2);
		s1.push_back(3);
		s1.push_back(4);
		s1.push_back(5);
		s1.printf_vector(s1);
		/*vector<int>s2(s1);*/
		vector<int> s2;
		s2.push_back(10);
		s2.push_back(20);
		s2.push_back(30);
		s2.printf_vector(s2);
		s1 = s2;
		s1.printf_vector(s1);
	}
	void test5() {
		vector<int> s1(10, 2);
		s1.printf_vector(s1);
		vector<char> s2(10, 'x');
		s2.printf_vector(s2);
		/*vector<int> s2(s1.begin() + 2, s1.end());*/
		vector<int> s3 = { 1,2,3,4,5,6 };
		s3.printf_vector(s3);
	}
	void test6() {
		vector<string> s1;
		s1.push_back("111111");
		s1.push_back("222222");
		s1.push_back("333333");
		s1.push_back("444444");
		s1.push_back("555555");
		s1.push_back("666666");
		s1.printf_vector(s1);

	}

};

